﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emulator.Base;

namespace Emulator.GameBoy.Memory
{
    public class GameBoyMemory:MemoryBase
    {
        //total 64KB 
        byte[] xMemory = new byte[64*1024];

        public byte[] MemoryData { get { 
            return xMemory;
        } }

        public byte PalleteRegister { get { return xMemory[0xFF47];} }
        public byte IERegister { get { return xMemory[0xFFFF]; } }
        public byte InterruptRequestFlag { get { return xMemory[0xFF0F]; } }

        public void ResetMemory(byte[] aRomContent)
        {         
            xMemory[0xFF05]=0x00;
			xMemory[0xFF06]=0x00;
			xMemory[0xFF07]=0x00;
			xMemory[0xFF10]=0x80;
			xMemory[0xFF11]=0xBF;
			xMemory[0xFF12]=0xF3;
			xMemory[0xFF14]=0xBF;
			xMemory[0xFF16]=0x3F;
			xMemory[0xFF17]=0x00;
			xMemory[0xFF19]=0xBF;
			xMemory[0xFF1A]=0x7F;
			xMemory[0xFF1B]=0xFF;
			xMemory[0xFF1C]=0x9F;
			xMemory[0xFF1E]=0xBF;
			xMemory[0xFF20]=0xFF;
			xMemory[0xFF21]=0x00;
			xMemory[0xFF22]=0x00;
			xMemory[0xFF23]=0xBF;
			xMemory[0xFF24]=0x77;
			xMemory[0xFF25]=0xF3;
            xMemory[0xFF26] = 0xF1;//-GB,F0-SGB;
			xMemory[0xFF40]=0x91;
			xMemory[0xFF42]=0x00;
			xMemory[0xFF43]=0x00;
			xMemory[0xFF45]=0x00;
			xMemory[0xFF47]=0xFC;
			xMemory[0xFF48]=0xFF;
			xMemory[0xFF49]=0xFF;
			xMemory[0xFF4A]=0x00;
			xMemory[0xFF4B]=0x00;
			xMemory[0xFFFF]=0x00;

            Array.Copy(aRomContent, 0, xMemory, 0, aRomContent.Length > 32 * 1024 ? 32 * 1024 : aRomContent.Length);
            //Array.Copy(aRomContent, 0, xMemory, 0, aRomContent.Length > 32 * 1024 ? 32 * 1024 : aRomContent.Length);
        }

        public override UInt16 MemoryLength
        {
            get
            {
                return (UInt16)xMemory.Length;
            }
        }

        public override byte Read8(UInt16 aAddress)
        {
            if (aAddress == 0xFF04)
                throw new Exception();

            if (aAddress == 0xFF05)
                throw new Exception();

            if (aAddress == 0xFF06)
                throw new Exception();

            if (aAddress == 0xFF07)
                throw new Exception();
            return xMemory[aAddress];
        }

        public override void Write8(UInt16 aAddress, byte aValue)
        {
            if (aAddress >= 0xC000 && aAddress <= 0xDE00)//Echo of 8kB Internal RAM
                xMemory[aAddress - 0xC000 + 0xE000] = aValue;

            if (aAddress >= 0xE000 && aAddress <= 0xFE00)
                xMemory[aAddress - 0xE000 + 0xC000] = aValue;
            xMemory[aAddress] = aValue;
        }

#if DEBUG
        public string OutputGPURegister()
        {
            StringBuilder mSB = new StringBuilder();
            mSB.Append("BG PaletteRegister:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF47],2).PadLeft(8,'0'));
            mSB.Append("OBP0 PaletteRegister:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF48], 2).PadLeft(8, '0'));
            mSB.Append("OBP1 PaletteRegister:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF49], 2).PadLeft(8, '0'));
            mSB.Append("LCDC Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF40], 2).PadLeft(8, '0'));
            mSB.Append("LCDC Status Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF41], 2).PadLeft(8, '0'));
            mSB.Append("SCY Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF42], 2).PadLeft(8, '0'));
            mSB.Append("SCX Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF43], 2).PadLeft(8, '0'));
            mSB.Append("LY Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF44], 2).PadLeft(8, '0'));
            mSB.Append("LYC Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF45], 2).PadLeft(8, '0'));
            mSB.Append("WY Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF4A], 2).PadLeft(8, '0'));
            mSB.Append("WX Register:");
            mSB.AppendLine(Convert.ToString(xMemory[0xFF4B], 2).PadLeft(8, '0'));
            return mSB.ToString();
        }

        public string OutputRAMString()
        {
            StringBuilder mSB = new StringBuilder();
            int mIndexCounter = 8;
            int mRAMBase = 0x0000;
            foreach (byte mMemory in MemoryData)
            {
                if (mIndexCounter % 8 == 0)
                {
                    mSB.Append(Convert.ToString(mRAMBase, 16).PadLeft(4, '0'));
                    mSB.Append(":");
                }
                mSB.Append(Convert.ToString(mMemory, 16).PadLeft(0, '2'));
                if (mIndexCounter == 1)
                {
                    mSB.Append("\r\n");
                    mIndexCounter = 8;
                }
                else
                {
                    mSB.Append(" ");
                    mIndexCounter--;
                }
                mRAMBase++;
            }
            return mSB.ToString();
        }
#endif
    }
}
